#include "test_album.h"

#include <stdio.h>

/*
 * pure virtual function test 
 */
template<typename T>
class Printer {
public:
  virtual void Print() const = 0;
  virtual T value() const = 0;
};

template<typename T>
class ColorPrinter : public Printer<T> {
public:
  ColorPrinter(T v) : data(v) { }
  void Print() const {
    printf("hello, the data is: %f\n", data);
  }
  T value() const {
    return data;
  }
  void test() {
    printf("hello, this is ColorPrinter test\n");
  }
private:
  T data;
};

/*
 * template specialization test
 */

template<int I, int J>
struct T_ {
  static const int i = I;
  static const int j = J;
};

template<typename T>
struct TT { };

// explict specialization can only be done in namespace scope
template<> struct TT<int> : T_<1, 1> { };

template<> struct TT<float> : T_<2, 2> { };

void PureVirtualFuncTest() {
  Printer<float> *p = new ColorPrinter<float>(100.f);
  //p->test();
  p->Print();
}
void SpecializationTest() {
  printf("%d, %d\n", TT<int>::i, TT<int>::j);
  printf("%d, %d\n", TT<float>::i, TT<float>::j);
}

// 

class CompanyA {
public:
  void sendCleartext(const std::string& msg) {
    printf("CompanyA, clear\n");
  }

  void sendEncrypted(const std::string& msg){
    printf("CompanyA, encrypted\n");
  }
};

class CompanyB {
public:
  void sendCleartext(const std::string& msg) {
    printf("CompanyB, clear\n");
  }

  void sendEncrypted(const std::string& msg) {
    printf("CompanyB, encrypted\n");
  }
};

class MsgInfo {  };                  // class for holding information

                                        // used to create a message

template<typename Company>
class MsgSender {
public:
  void sendClear(const MsgInfo& info) {
    std::string msg;    

    Company c;

    c.sendCleartext(msg);
  }



  void sendSecret(const MsgInfo& info) { 
    std::string msg;    

    Company c;
    c.sendEncrypted(msg);
  }

};

template<typename Company>
class LoggingMsgSender: public MsgSender<Company> {
public:

  void sendClearMsg(const MsgInfo& info) {
    //write "before sending" info to the log;

    this->sendClear(info); // this-> is not needed for vc

    //write "after sending" info to the log;

  }
};

void NameAccessTest() {
  LoggingMsgSender<CompanyA> sender;
  sender.sendClearMsg(MsgInfo());
}

namespace ct {
void TemplateTest::Run(int argc, char *argv[]) {
  NameAccessTest();
  PureVirtualFuncTest();
  SpecializationTest();
}
} // ct

